package com.demo.task.ui.screen

import android.util.Log
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.annotation.OptIn
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.net.toUri
import androidx.media3.common.MediaItem
import androidx.media3.common.PlaybackException
import androidx.media3.common.Player
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.DefaultRenderersFactory
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.mediacodec.MediaCodecSelector
import androidx.media3.exoplayer.mediacodec.MediaCodecUtil
import androidx.media3.ui.PlayerView
import com.demo.task.bean.PlanBean
import com.demo.task.ext.executeMain
import com.demo.task.ext.getResPath
import com.demo.task.ext.getUrlFileName
import com.demo.task.ext.launchIO
import com.demo.task.ext.pxToDp
import com.demo.task.ext.sendError
import com.demo.task.ext.sendIds
import com.demo.task.socket.RemoteInterface
import com.demo.task.vm.MainViewModel
import com.orhanobut.logger.Logger
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Job
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.json.JSONObject
import java.io.File
import kotlin.time.Duration.Companion.seconds

@OptIn(UnstableApi::class)
@Composable
fun Window(
    viewModel: MainViewModel,
    socketIO: RemoteInterface,
    box: PlanBean.Plan.Group.Page.Box
) {
    Box(
        Modifier
            .padding(start = box.x.pxToDp().dp, top = box.y.pxToDp().dp)
            .size(box.pixelsW.pxToDp().dp, box.pixelsH.pxToDp().dp)
    ) {
        var isReload = false
        var windows = box.list.map { it.copy() }

        var mark by remember { mutableStateOf(false) }
        var windowState by remember { mutableStateOf<PlanBean.Plan.Group.Page.Box.Window?>(null) }
        var awaitPlayer by remember { mutableStateOf<Job?>(null) }

        val context = LocalContext.current
        val playId by remember { mutableStateOf(MutableStateFlow("")) }

        val codecSelector = MediaCodecSelector { mimeType, secureDecoder, tunnelingDecoder ->
            MediaCodecUtil.getDecoderInfos(
                mimeType,
                secureDecoder,
                tunnelingDecoder
            ).filter {
                it.hardwareAccelerated && !it.softwareOnly
            }
        }

        val renderersFactory = DefaultRenderersFactory(context)
            .setMediaCodecSelector(codecSelector)
            .setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER)
            .forceEnableMediaCodecAsynchronousQueueing()

        val media3 = ExoPlayer.Builder(context, renderersFactory)
            .build()
            .apply {
                playWhenReady = true
            }

        val playerView = remember {
            PlayerView(context)
                .apply {
                    layoutParams = ViewGroup.LayoutParams(
                        MATCH_PARENT,
                        MATCH_PARENT
                    )
                    useController = false
                    player = media3
                }
        }

        val webView = remember {
            WebView(context).apply {
                setBackgroundColor(0)
                webViewClient = WebViewClient()
            }
        }

        val media3Listener = object : Player.Listener {
            private var mediaId = ""
            override fun onPlaybackStateChanged(playbackState: Int) {
                super.onPlaybackStateChanged(playbackState)
                Log.i(TAG, "onPlaybackStateChanged: $playbackState ${windowState?.id}")
                if (playbackState == Player.STATE_ENDED || playbackState == Player.STATE_IDLE) {
                    //Logger.i("onPlaybackStateChanged: $playbackState ${windowState?.id}")
                    // 视频播放完成
                    awaitPlayer?.cancel()
                }
            }

            override fun onPlayerError(exception: PlaybackException) {
                super.onPlayerError(exception)
                Log.e(TAG, "onPlayerError: $mediaId", exception)
                Logger.e(exception, "onPlayerError: $mediaId")
                socketIO.sendError(key = mediaId, remark = exception.message.orEmpty())
            }

            override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
                super.onMediaItemTransition(mediaItem, reason)
                mediaId = mediaItem?.mediaId.orEmpty()
                runBlocking { playId.emit(mediaId) }
            }
        }
        media3.addListener(media3Listener)

        //协程
        LaunchedEffect(box) {
            launch {
                viewModel.playComplete.collectLatest {
                    media3.seekTo(0, 0)
                    media3.play()
                }
            }

            launchIO {
                playId.collectLatest {
                    //Log.i(TAG, "playId.collectLatest: $it")
                    //socketIO.sendProgress(box.id, it)
                    socketIO.sendIds(it)
                }
            }

            launchIO {
                fun isMediaOfNext(index: Int): Boolean {
                    val nextIndex = index.plus(1)
                    if (nextIndex >= windows.size) return false
                    val window = windows[nextIndex]
                    return (window.type != 3 && window.qty >= 0)
                }

                while (true) {
                    while (windows.any { it.qty > 0 }) {
                        val medias = mutableListOf<MediaItem>()
                        for ((index, window) in windows.withIndex()) {
                            //判断是否要同步socket发过来的进度
                            if (isReload) {
                                isReload = false
                                break
                            }
                            //小于0跳过播放
                            if (window.qty-- < 0) {
                                continue
                            }

                            Log.i(TAG, "Window for withIndex: $index $window")
                            Logger.i("Window for withIndex: $index $window")

                            //初始化webView需要的东西
                            if (window.type == 3) {
                                executeMain {
                                    webView.loadData(window.content, "text/html", "UTF-8")
                                }
                                playId.emit(window.id)
                                windowState = window
                                awaitPlayer = launch(start = CoroutineStart.LAZY) {
                                    delay(window.hold.seconds)
                                }
                            } else {
                                val fileName = window.content.getUrlFileName()
                                val file = File(getResPath(), fileName)
                                val mediaItem = MediaItem.Builder()
                                    .setUri(file.toUri())
                                    .setMediaId(window.id)
                                    .apply {
                                        if (window.type == 2) {
                                            setImageDurationMs(window.hold * 1000L)
                                        }
                                    }
                                    .build()
                                medias.add(mediaItem)

                                //如果是媒体类型继续添加mediaItem
                                if (isMediaOfNext(index)) continue

                                //开始播放mediaItems
                                executeMain {
                                    media3.setMediaItems(medias)
                                    media3.prepare()
                                    media3.seekTo(0, 0)
                                }
                                medias.clear()
                                windowState = window
                                awaitPlayer = launch(start = CoroutineStart.LAZY) {
                                    awaitCancellation()
                                }
                            }

                            awaitPlayer?.join()
                            delay(1_000)
                        }
                    }
                    //重置qty
                    windows = box.list.map { it.copy() }
                    viewModel.notifyAwait(box.id)
                }
            }

            //监听socket消息(从机)
            launch {
                socketIO.msg.collectLatest { msg ->
                    val jsonObject = runCatching { JSONObject(msg) }.getOrNull()
                    if (box.id == jsonObject?.optString("boxId")) {
                        val list = box.list.map { it.copy() }
                        val id = jsonObject.optString("contentId")
                        val qty = jsonObject.optInt("qty")
                        for (window in list) {
                            val currentQty = window.qty--
                            if (window.id == id && currentQty <= qty) {
                                break
                            }
                        }
                        isReload = true
                        windows = list
                        awaitPlayer?.join()
                    }
                }
            }


            if (box.flag) {
                launch {
                    viewModel.gpsManager.visOverlay.collectLatest {
                        mark = !it
                    }
                }
            }
        }


        //界面加载
        windowState?.also { window ->
            Log.i(TAG, "windowState: $window")
            Logger.i("windowState: $window")
            when (window.type) {
                in 1..2 -> AndroidView(factory = { playerView }, update = { media3.play() })

                3 -> AndroidView(factory = { webView })
            }

            if (mark) {
                Spacer(
                    modifier = Modifier
                        .fillMaxSize()
                        .background(Color.Black)
                )
            }
        }

        //生命周期Dispose
        DisposableEffect(Unit) {
            onDispose {
                Log.i(TAG, "onDispose: ${box.id}")
                Logger.i("onDispose: ${box.id}")
                //media3.clearMediaItems()
                //media3.removeListener(media3Listener)
                media3.run {
                    stop()
                    clearMediaItems()
                    clearVideoSurface()
                    release()
                }
                webView.destroy()
                awaitPlayer?.cancel()
                System.gc()
            }
        }
    }
}


private const val TAG = "WindowScreen"


